﻿using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using System.Linq.Expressions;

namespace ProxyServer.EntityFrameworkCore.ValueConverts
{
    public class LocalDateTimeValueConverter : ValueConverter<DateTime, DateTime>
    {
        static readonly Expression<Func<DateTime, DateTime>> ConvertToUTC =
           (DateTime time) => time.Kind == DateTimeKind.Utc || time.Kind == DateTimeKind.Unspecified ?
                               time :
                               TimeZoneInfo.ConvertTimeToUtc(time);

        static readonly Expression<Func<DateTime, DateTime>> ConvertFromUTC =
            (DateTime time) => time.Kind != DateTimeKind.Utc || time.Kind == DateTimeKind.Unspecified ?
                                time :
                                time.ToLocalTime();

        private LocalDateTimeValueConverter() : base(ConvertToUTC, ConvertFromUTC)
        {

        }

        public static readonly ValueConverter<DateTime, DateTime> Singlten = new LocalDateTimeValueConverter();
    }

    public class LocalDateTimeOffsetValueConverter : ValueConverter<DateTimeOffset, DateTimeOffset>
    {
        static readonly TimeSpan ZeroOffset = TimeSpan.Zero;

        static readonly Expression<Func<DateTimeOffset, DateTimeOffset>> ConvertToUTC =
            (DateTimeOffset time) => time.Offset == ZeroOffset ? time : time.ToOffset(ZeroOffset);

        static readonly Expression<Func<DateTimeOffset, DateTimeOffset>> ConvertFromUTC =
            (DateTimeOffset time) => time.Offset != ZeroOffset ? time : time.ToLocalTime();

        private LocalDateTimeOffsetValueConverter() : base(ConvertToUTC, ConvertFromUTC)
        {

        }


        public static readonly ValueConverter<DateTimeOffset, DateTimeOffset> Singleton = new LocalDateTimeOffsetValueConverter();
    }

    public class JsonStringValueConverter<T> : ValueConverter<T, string?>
        where T : class
    {
        public JsonStringValueConverter() : this(default(T)!)
        {

        }

        public JsonStringValueConverter(T value) : base(
            v => Serialize(v, value),
            v => Deserialize(v, value))
        {

        }

        static string? Serialize(T v, T defaultValue)
        {
            var current = v ?? defaultValue;
            if (current is null)
            {
                return null;
            }
            return System.Text.Json.JsonSerializer.Serialize(current, (System.Text.Json.JsonSerializerOptions?)null);
        }

        static T Deserialize(string? v, T defaultValue)
        {
            if(string.IsNullOrWhiteSpace(v))
            {
                return defaultValue;
            }

            return System.Text.Json.JsonSerializer.Deserialize<T>(v, (System.Text.Json.JsonSerializerOptions?)null)!;
        }
    }
}
